package com.kamistoat.meimeistore.commoncore.utils.file;

import com.kamistoat.meimeistore.commoncore.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * 文件处理工具类
 * 理解文件处理
 */
public class FileUtils {
    // 字符常量--斜杠
    public static final char SLASH = '/';

    // 字符常量--反斜杠。需要使用转义
    public static final char BACKSLASH = '\\';

    // 文件名正则匹配，用于匹配文件名
    public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";

    /**
     * 将指定文件转换为字节输出流
     *
     * @param filePath
     * @param outputStream
     * @throws IOException
     */
    public static void writeBytes(String filePath, OutputStream outputStream) throws IOException {
        FileInputStream fileInputStream = null;
        try {
            // 按照路径建立文件句柄
            File file = new File(filePath);
            if (!file.exists()) {
                // 如果文件句柄指向为空，抛出文件不存在异常
                throw new FileNotFoundException();
            }
            // 使用文件句柄建立输入流
            fileInputStream = new FileInputStream(file);
            // 1024字节长度将作为缓冲流
            byte[] bytes = new byte[1024];
            int length;
            while ((length = fileInputStream.read(bytes)) > 0) {
                // 每次最多从输入流中读取1024字节到缓冲流中。然后将缓冲流中非空的部分写入输出流
                outputStream.write(bytes, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            // 无论成功与否，都应该在最后关闭文件输入流和文件输出流
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 删除文件
     *
     * @param filePath 文件路径
     * @return
     */
    public static boolean deleteFile(String filePath) {
        boolean flag = false;
        // 建立文件句柄
        File file = new File(filePath);
        // 文件句柄指向非空且确实是文件(排除文件夹)
        if (file.exists() && file.isFile()) {
            // 最终能否成功还要看 delete的执行结果
            flag = file.delete();
        }
        return flag;
    }

    /**
     * 验证文件名是否合法
     *
     * @param filename 文件名
     * @return
     */
    public static boolean isValidFilename(String filename) {
        return filename.matches(FILENAME_PATTERN);
    }

    /**
     * 检查资源是否可以下载
     *
     * @param resource 资源路径
     * @return
     */
    public static boolean checkAllowDownload(String resource) {
        // 禁止目录上跳级别
        if (StringUtils.contains(resource, "..")) {
            return false;
        }
        // 检查允许下载的文件类型
        // 使用 Apache的 ArrayUtils.contains([],target) 可以快速判断数组中是否包含目标值
        if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) {
            return true;
        }

        return false;
    }

    /**
     * 从请求头中获得编码规则，对下载资源名称重新编码
     *
     * @param httpServletRequest 请求头
     * @param filename           资源名
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String setFileDownloadHeader(HttpServletRequest httpServletRequest, String filename) throws UnsupportedEncodingException {
        // USER-AGENT 是请求头中的固定字段，用于表示标识请求发起者的详细信息
        final String user_agent = httpServletRequest.getHeader("USER_AGENT");
        String filename_temp = filename;
        // 根据请求来自不同的游览器，对下载资源进行对应的编码
        if (user_agent.contains("MSIE")) {
            // 微软IE游览器
            filename_temp = URLEncoder.encode(filename_temp, "utf-8");
            filename_temp = filename_temp.replace("+", " ");
        } else if (user_agent.contains("Firefox")) {
            // 火狐游览器
            filename_temp = new String(filename.getBytes(), "ISO8859-1");
        } else if (user_agent.contains("Chrome")) {
            // google浏览器
            filename_temp = URLEncoder.encode(filename_temp, "utf-8");
        } else {
            // 其它浏览器
            filename_temp = URLEncoder.encode(filename_temp, "utf-8");
        }
        return filename_temp;
    }

    /**
     * 根据文件路径返回文件名
     *
     * @param filePath 文件路径
     * @return
     */
    public static String getName(String filePath) {
        // 如果路径为空或者""则返回""
        if (StringUtils.isEmpty(filePath)) {
            return StringUtils.EMPTY;
        }
        int len = filePath.length();

        // 如果路径是 /D:/abc/x.mp4/的格式，则去掉最后一个分隔符
        if (isFileSeparator(filePath.charAt(len - 1))) {
            len--;
        }

        int begin = 0;
        char c;
        // len-1是因为下标从0开始
        // 寻找最后一个分隔符
        for (int i = len - 1; i >= 0; i--) {
            c = filePath.charAt(i);
            if (isFileSeparator(c)) {
                begin = i + 1;
                break;
            }
        }

        return filePath.substring(begin, len);
    }

    /**
     * 判断是否为 windows或者Linux文件分隔符
     * w平台下分隔符为斜杠\ l平台下分隔符为反斜杠/
     *
     * @param c
     * @return
     */
    public static boolean isFileSeparator(char c) {
        return c == SLASH || c == BACKSLASH;
    }


    /**
     * 对下载文件名重新编码后放入到 Response中
     *
     * @param response
     * @param realFileName
     * @throws UnsupportedEncodingException
     */
    public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {
        String percentEncodedFileName = percentEncode(realFileName);

        StringBuilder contentDispositionValue = new StringBuilder();
        contentDispositionValue.append("attachment; filename=")
                .append(percentEncodedFileName)
                .append(";")
                .append("filename*=")
                .append("utf-8''")
                .append(percentEncodedFileName);

        response.setHeader("Content-disposition", contentDispositionValue.toString());
        response.setHeader("download-filename", percentEncodedFileName);
    }

    /**
     * 百分号编码.因为有的时候空格会被编码成+有时被编码成%20，所以这里是统一将+替换成 %20
     * @param s
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String percentEncode(String s) throws UnsupportedEncodingException {
        String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
        return encode.replaceAll("\\+", "%20");
    }

}































